package ewan.android.droidjockey;

import java.io.BufferedWriter;

import java.io.File;
import java.io.FileWriter;
import java.net.URL;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Properties;
import java.util.Random;
import java.util.Map.Entry;
import android.location.Location;
import android.location.LocationManager;
import java.util.ArrayList;
import javax.mail.Folder;
import javax.mail.MessagingException;
import javax.mail.Store;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;
import com.echonest.api.v4.*;
import ewan.android.droidjockey.R;
import de.umass.lastfm.*;
import de.umass.lastfm.Track;
import de.umass.lastfm.cache.FileSystemCache;
import ewan.android.droidjockey.MusicRetriever.Item;
import android.app.Fragment;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.database.Cursor;
import android.graphics.Color;

import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.preference.PreferenceManager;
import android.provider.CalendarContract.Calendars;
import android.text.TextUtils.TruncateAt;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.ToggleButton;
import android.speech.tts.TextToSpeech;
import android.speech.tts.TextToSpeech.OnUtteranceCompletedListener;
import android.speech.tts.TextToSpeech.*;

public class MainFragment extends Fragment implements OnClickListener,
		OnInitListener, OnLongClickListener, OnUtteranceCompletedListener {

	public static final ArrayAdapter<String> songList = null;
	private static final int MY_DATA_CHECK_CODE = 1234;
	
	public final String RSSFEED = "http://news.google.com/news?pz=1&cf=all&ned=uk&hl=en&output=rss";
	private RSSFeed feed = null;

	Button mPlayButton;
	Button mPauseButton;
	Button mSkipButton;
	Button mRewindButton;
	Button mSongList;
	Button mRepeat;
	Button mShuffle;
	
	Button tabletPopulate;
	Button tabletPlaylist;
	ToggleButton tabletDJ;
	Button tabletSettings;
	
	ImageView mAlbumArt;
	SeekBar mSeekbar;
	TextView albumTitle;
	TextView songTitle;
	TextView artistTitle;
	TextView progressed;
	TextView remaining;
	View main;
	int pos;
	Thread query;
	BufferedWriter bw;
	FileWriter fw;
	File outputFile;
	FileSystemCache cache;
	boolean ready = false;
	static boolean djMode = false;
	ProgressBar progress;

	Random mRandom = new Random();
	
	int databaseSize;

	boolean notPlayed = false;
	boolean threadwait = false;
	boolean UIwait = false;
	boolean gotMail;
	boolean gotNews;
	boolean gotTourDates;
	boolean emailSetup = false;
	static boolean updatingDatabase = false;
	boolean generatingPlaylist = false;

	String tourArtist = null;
	static String userEmail = "";
	static String userPassword = "";

	long timeRemaining;
	long timeProgressed;
	ContentResolver cr = null;

	static ArrayList<String> emails = new ArrayList<String>();
	static ArrayList<String> headlines = new ArrayList<String>();
	static ArrayList<Event> tour = new ArrayList<Event>();
	
	static ArrayList<String> mentionedTourArtists = new ArrayList<String>();

	int oldEmailNumber;
	int newEmailNumber;
	int djModeTimeout = 0;

	//public TextToSpeech mTts;

	/*public void onActivityResult(int requestCode, int resultCode, Intent data) {
		Context ctx = (Context) MainFragment.this.getActivity();
		if (requestCode == MY_DATA_CHECK_CODE) {
			if (resultCode == TextToSpeech.Engine.CHECK_VOICE_DATA_PASS) {
				// success, create the TTS instance
				mTts = new TextToSpeech(ctx, this);
				mTts.setOnUtteranceCompletedListener(this);
				HashMap<String, String> myHashAlarm = new HashMap();
				myHashAlarm
						.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, "Ended");
			} else {
				// missing data, install it
				Intent installIntent = new Intent();
				installIntent
						.setAction(TextToSpeech.Engine.ACTION_INSTALL_TTS_DATA);
				startActivity(installIntent);

			}
		}
	}*/

	@Override
	public void onConfigurationChanged(Configuration newConfig) {
		super.onConfigurationChanged(newConfig);
	}

	/**
	 * Called when the activity is first created. Here, we simply set the event
	 * listeners and start the background service ({@link MusicService}) that
	 * will handle the actual media playback.
	 */
	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container,
			Bundle savedInstanceState) {

		super.onCreate(savedInstanceState);
		
		Context ctx = (Context) MainFragment.this.getActivity();
		cr = ctx.getContentResolver();
		// Set up the text to speech.

		Intent checkIntent = new Intent();
		checkIntent.setAction(TextToSpeech.Engine.ACTION_CHECK_TTS_DATA);
		startActivityForResult(checkIntent, MY_DATA_CHECK_CODE);
		

		setHasOptionsMenu(true);
		setRetainInstance(true);
		View main = inflater.inflate(R.layout.main, container, false);

		if (!ready) {
			ctx.startService(new Intent(MusicService.ACTION_READY));

			// This sets up a cache for the lastFM API. This is required or the
			// API will cause the program to crash.
			try {
				outputFile = File.createTempFile("LastFM", "txt",
						ctx.getCacheDir());

				FileSystemCache cache = new FileSystemCache(ctx.getCacheDir());
				cache.clear();
				cache = new FileSystemCache(ctx.getCacheDir());
				Caller.getInstance().setCache(cache);
				Caller.getInstance().setDebugMode(true);

			} catch (Exception e) {
			}
			ready = true;
		}

		// If we need to, start the threads running.

		try {
			if (!thread.isAlive()) {
				thread.start();
			}
			if (!UIThread.isAlive()) {
				UIThread.start();
			}
			if (!OnlineChecker.isAlive()) {
				OnlineChecker.start();
			}
		} catch (Exception e) {
		}

		// Assign the buttons to their corresponding XML layout counterparts.

		mPlayButton = (Button) main.findViewById(R.id.playbutton);
		mPauseButton = (Button) main.findViewById(R.id.pausebutton);
		mPauseButton.setVisibility(View.GONE);
		mSkipButton = (Button) main.findViewById(R.id.skipbutton);
		mRewindButton = (Button) main.findViewById(R.id.rewindbutton);
		mSeekbar = (SeekBar) main.findViewById(R.id.seekbar);
		mSongList = (Button) main.findViewById(R.id.songlist);
		albumTitle = ((TextView) main.findViewById(R.id.album_title));
		songTitle = ((TextView) main.findViewById(R.id.song_title));
		artistTitle = ((TextView) main.findViewById(R.id.artist_title));
		progressed = ((TextView) main.findViewById(R.id.timepassed));
		remaining = ((TextView) main.findViewById(R.id.timeremaining));
		mAlbumArt = ((ImageView) main.findViewById(R.id.imageView1));
		progress = (ProgressBar) main.findViewById(R.id.progress);
		mRepeat = (Button) main.findViewById(R.id.repeat);
		mShuffle = (Button) main.findViewById(R.id.shuffle);
		mAlbumArt.setImageBitmap(null);
		try {
			tabletPopulate = (Button) main.findViewById(R.id.populate);
			tabletPlaylist = (Button) main.findViewById(R.id.playlist);
			tabletDJ = (ToggleButton) main.findViewById(R.id.djtoggle);
			tabletSettings = (Button) main.findViewById(R.id.djsettings);
			
		} catch (Exception e){}

		// Set up the buttons to use the onClick method.

		mPlayButton.setOnClickListener(this);
		mPauseButton.setOnClickListener(this);
		mSkipButton.setOnClickListener(this);
		mSkipButton.setOnLongClickListener(this);
		mRewindButton.setOnClickListener(this);
		mRewindButton.setOnLongClickListener(this);
		mSongList.setOnClickListener(this);
		mShuffle.setOnClickListener(this);
		mRepeat.setOnClickListener(this);
		try {
			tabletPopulate.setOnClickListener(this);
			tabletPlaylist.setOnClickListener(this);
			tabletDJ.setOnClickListener(this);
			tabletSettings.setOnClickListener(this);
		} catch (Exception e) {}

		// Change the repeat and shuffle icons depending on the current status.
		// This is needed for rotation changes when the view is recreated.

		if (!MusicRetriever.repeat) {
			mRepeat.setBackgroundResource(R.drawable.ic_menu_rotatedark);
		} else {
			mRepeat.setBackgroundResource(R.drawable.ic_menu_rotate);
		}

		if (!MusicRetriever.shuffle) {
			mShuffle.setBackgroundResource(R.drawable.ic_menu_shuffledark);
		} else {
			mShuffle.setBackgroundResource(R.drawable.ic_menu_shuffle);
		}

		mSeekbar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {

			public void onProgressChanged(SeekBar seekbar, int p,
					boolean fromUser) {
				if (seekbar == mSeekbar) {
					if (fromUser) {
						pos = p;
					}
				}
			}

			public void onStartTrackingTouch(SeekBar seekBar) {
			}

			/**
			 * When the user lets go of the seekbar we update the position
			 * 
			 */
			public void onStopTrackingTouch(SeekBar seekBar) {
				if (MusicService.mPlayer != null) {
					MusicService.mPlayer.seekTo(pos);
					Message position = new Message();
					position.what = pos;
					threadHandler.sendMessage(position);
				}
			}
		});
		return main;
	}

	public boolean onOptionsItemSelected(MenuItem item) {
		Context ctx = (Context) MainFragment.this.getActivity();
		// This is our menu. Here the user can populate their database and
		// generate a playlist.

		switch (item.getItemId()) {

		// Generating a playlist

		case R.id.new_playlist:
			new PlaylistGenerator().execute();
			return true;

			// Populating the database

		case R.id.construct_database:
			if (!updatingDatabase){
				new DatabaseManagement().execute();
			}
			else {
				Toast.makeText(ctx, "Update In Progress", Toast.LENGTH_SHORT).show();
			}
			return true;
			
		case R.id.status_database:
			SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
			Toast.makeText(ctx, sharedPreferences.getInt("database", 0) + " tracks in database", Toast.LENGTH_SHORT).show(); 
			if (sharedPreferences.getInt("database", 0) == MusicRetriever.mItems.size()){
				Toast.makeText(ctx, "All tracks in database" , Toast.LENGTH_SHORT).show(); 
			}
			return true;

		case R.id.dj_mode:
			djMode = !djMode;
			if (djMode) {
				Toast.makeText(ctx, "DJ on", Toast.LENGTH_SHORT).show();
			} else {
				Toast.makeText(ctx, "DJ off", Toast.LENGTH_SHORT).show();
				mentionedTourArtists.clear();
			}
			return true;
		case R.id.settings:
			ctx.startActivity(new Intent(ctx, Settings.class));
			return true;
		default:
			return super.onOptionsItemSelected(item);
		}

	}

	public void serviceStarter(Intent intent) {
		Context ctx = (Context) MainFragment.this.getActivity();
		ctx.startService(intent);
	}

	// Button Listeners

	public synchronized void onClick(View target) {

		Context ctx = (Context) MainFragment.this.getActivity();

		// Send the correct intent to the MusicService, according to the button
		// that was clicked

		// Sends a play request. Displays the pause button and hides the play
		// button.

		if (target == mPlayButton) {
			ctx.startService(new Intent(MusicService.ACTION_PLAY));
			Message playing = new Message();
			playing.what = 2;
			UIHandler.sendMessage(playing);
		}

		// Sends a pause request. Displays the play button and hides the pause
		// button.

		else if (target == mPauseButton) {
			ctx.startService(new Intent(MusicService.ACTION_PAUSE));
			Message paused = new Message();
			paused.what = 1;
			UIHandler.sendMessage(paused);
		}

		// Sends a skip request. Moves to the next song in the playlist.

		else if (target == mSkipButton) {
			ctx.startService(new Intent(MusicService.ACTION_SKIP));
			// speak();
			Message position = new Message();
			position.what = 0;
			threadHandler.sendMessage(position);

		}

		// Sends a rewind request. Moves to the previous song in the playlist

		else if (target == mRewindButton) {
			ctx.startService(new Intent(MusicService.ACTION_REWIND));
			Message position = new Message();
			position.what = 0;
			threadHandler.sendMessage(position);
		}

		// Changes the view to the songlist.

		else if (target == mSongList) {

			ctx.startActivity(new Intent(ctx, SongList.class));

			// Shuffles or un-shuffles the current playlist and changes the
			// icon.

		} else if (target == mShuffle) {
			ctx.startService(new Intent(MusicService.ACTION_SHUFFLE));

			if (MusicRetriever.shuffle) {
				mShuffle.setBackgroundResource(R.drawable.ic_menu_shuffledark);
			} else {
				mShuffle.setBackgroundResource(R.drawable.ic_menu_shuffle);
			}

			// Enables or disables repeat mode and changes the icon.

		} else if (target == mRepeat) {
			ctx.startService(new Intent(MusicService.ACTION_REPEAT));
			if (MusicRetriever.repeat) {
				mRepeat.setBackgroundResource(R.drawable.ic_menu_rotatedark);
			} else {
				mRepeat.setBackgroundResource(R.drawable.ic_menu_rotate);
			}
		}
		else if (target == tabletPopulate){
			if (!updatingDatabase){
				new DatabaseManagement().execute();
			}
			else {
				Toast.makeText(ctx, "Update In Progress", Toast.LENGTH_SHORT).show();
			}
		}
		else if (target == tabletPlaylist){
			new PlaylistGenerator().execute();
		}
		else if (target == tabletDJ){
			djMode = !djMode;
			if (djMode) {
				Toast.makeText(ctx, "DJ on", Toast.LENGTH_SHORT).show();
			} else {
				Toast.makeText(ctx, "DJ off", Toast.LENGTH_SHORT).show();
				mentionedTourArtists.clear();
			}
		}
		else if (target == tabletSettings){
			ctx.startActivity(new Intent(ctx, Settings.class));
		}


	}

	public boolean onLongClick(View target) {
		Context ctx = (Context) MainFragment.this.getActivity();

		// Still a work in progress, should increase the speed forward or back
		// by holding the corresponding button.
		// Currently only advances or rewinds once on hold.

		if (target == mSkipButton) {
			ctx.startService(new Intent(MusicService.ACTION_FORWARD));

		} else if (target == mRewindButton) {
			ctx.startService(new Intent(MusicService.ACTION_BACK));
		}
		return true;
	}

	// Async Tasks


	public class DJSpeech extends AsyncTask<Void, Void, Void>  {
		Context ctx = (Context) MainFragment.this.getActivity();
		SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
		protected synchronized void onPreExecute() {

			ctx.startService(new Intent(MusicService.ACTION_PAUSE));
			Message paused = new Message();
			paused.what = 1;
			UIHandler.sendMessage(paused);
		
		}

		@SuppressWarnings({ "unchecked", "rawtypes" })
		protected Void doInBackground(Void... params) {
			HashMap<String, String> myHashAlarm = new HashMap();
			myHashAlarm
					.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, "Ended");
			String myText1 = null;
			try {
				if (gotMail && sharedPreferences.getBoolean("emailsChecked", true)) {
					myText1 = "You have a new email; " + emails.get(0);
					MainActivity.mTts.speak(myText1, TextToSpeech.QUEUE_ADD, myHashAlarm);
					gotMail = false;

				} else if (gotTourDates && sharedPreferences.getBoolean("concertsChecked", true)) {
					myText1 = tourArtist
							+ " is playing "
							+ tour.get(0).getVenue().getName()
							+ " on "
							+ tour.get(0)
									.getEndDate()
									.toGMTString()
									.substring(
											0,
											tour.get(0).getEndDate()
													.toGMTString().length() - 9);
					MainActivity.mTts.speak(myText1, TextToSpeech.QUEUE_ADD, myHashAlarm);
					mentionedTourArtists.add(tourArtist);
					gotTourDates = false;

				} else if (gotNews && sharedPreferences.getBoolean("newsChecked", true)) {
					int newsSelection = mRandom.nextInt(5);
					myText1 = "In the news today; "
							+ headlines.get(newsSelection);
					MainActivity.mTts.speak(myText1, TextToSpeech.QUEUE_ADD, myHashAlarm);
					gotNews = false;

				} else {
					int selection = mRandom.nextInt(3);

					if (selection == 0) {

						myText1 = "This is "
								+ MusicRetriever.getCurrentSong().getArtist()
										.toString()
								+ " with "
								+ MusicRetriever.getCurrentSong().getTitle()
										.toString();
					} else if (selection == 1) {

						myText1 = "Next up is "
								+ MusicRetriever.getCurrentSong().getArtist()
										.toString();
					} else if (selection == 2) {

						myText1 = "Now playing "
								+ MusicRetriever.getCurrentSong().getArtist()
										.toString();
					} else if (selection == 3) {

						myText1 = MusicRetriever.getCurrentSong().getTitle().toString();
					}

					MainActivity.mTts.speak(myText1, TextToSpeech.QUEUE_ADD, myHashAlarm);
				}

			} catch (Exception e) {

			}
			return null;
		}

		protected synchronized void onPostExecute(Void result) {

		}


	}
	
	public void onUtteranceCompleted(String utteranceId) {

		Context ctx = (Context) MainFragment.this.getActivity();
		ctx.startService(new Intent(MusicService.ACTION_PLAY));
		Message playing = new Message();
		playing.what = 2;
		UIHandler.sendMessage(playing);

	}

	public class DatabaseManagement extends AsyncTask<Void, Void, Void> {

		Context ctx = (Context) MainFragment.this.getActivity();

		protected synchronized void onPreExecute() {
			updatingDatabase = true;
			Toast.makeText(ctx, "Updating database", Toast.LENGTH_SHORT).show();
			mSongList.setTextColor(Color.parseColor("#99CC00"));
			albumTitle.setTextColor(Color.parseColor("#99CC00"));
			songTitle.setTextColor(Color.parseColor("#99CC00"));
			artistTitle.setTextColor(Color.parseColor("#99CC00"));

		}

		protected Void doInBackground(Void... params) {
			try {
				fillDatabase();
			} catch (EchoNestException e) {
				e.printStackTrace();
			}
			return null;
		}

		protected synchronized void onPostExecute(Void result) {
			updatingDatabase = false;
			Toast.makeText(ctx, "Database updated", Toast.LENGTH_SHORT).show();
			mSongList.setTextColor(Color.parseColor("#FFFFFF"));
			albumTitle.setTextColor(Color.parseColor("#FFFFFF"));
			songTitle.setTextColor(Color.parseColor("#FFFFFF"));
			artistTitle.setTextColor(Color.parseColor("#FFFFFF"));
		}

	}

	public class PlaylistGenerator extends AsyncTask<Void, Void, Void> {

		protected synchronized void onPreExecute() {
			generatingPlaylist = true;
			mSongList.setTextColor(Color.parseColor("#33B5E5"));
			albumTitle.setTextColor(Color.parseColor("#33B5E5"));
			songTitle.setTextColor(Color.parseColor("#33B5E5"));
			artistTitle.setTextColor(Color.parseColor("#33B5E5"));

		}

		protected Void doInBackground(Void... params) {

			try {
				processQueryRequest(MusicRetriever.getCurrentSong().getArtist()
						.toString(), MusicRetriever.getCurrentSong().getTitle()
						.toString());
			} catch (EchoNestException e) {
				e.printStackTrace();
			} catch (Exception e) {
				e.printStackTrace();
			}
			return null;
		}

		protected synchronized void onPostExecute(Void result) {
			generatingPlaylist = false;
			mSongList.setTextColor(Color.parseColor("#FFFFFF"));
			albumTitle.setTextColor(Color.parseColor("#FFFFFF"));
			songTitle.setTextColor(Color.parseColor("#FFFFFF"));
			artistTitle.setTextColor(Color.parseColor("#FFFFFF"));
		}

	}


	// Threads

	/**
	 * Handles the updating of the UI. Checks to see if the current song has
	 * changed, if it has updates the UI accordingly. Also ensures the
	 * play/pause buttons are correctly displayed depending on the state of
	 * playback.
	 */
	Thread UIThread = new Thread() {
		
		@Override
		public synchronized void run() {
			SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
			while (true) {
				synchronized (this) {
					while (UIwait) {
						try {
							wait();
						} catch (Exception e) {
						}
					}
				}

				try {

					// If any of the text items has changed, update the UI.

					if (MusicService.State.Playing != null) {
						if (!artistTitle.getText().equals(
								MusicRetriever.getCurrentSong().getArtist()
										.toString())
								|| (!songTitle.getText().equals(
										MusicRetriever.getCurrentSong()
												.getTitle().toString()))
								|| (!albumTitle.getText().equals(
										MusicRetriever.getCurrentSong()
												.getAlbum().toString()))) {
							if (djMode) {
								int selection = mRandom.nextInt(4);
								if (selection == 1 && sharedPreferences.getBoolean("songInfoChecked", true)) {
									new DJSpeech().execute();

								}
								else if ((sharedPreferences.getBoolean("emailsChecked", true) && gotMail) || (sharedPreferences.getBoolean("newsChecked", true) && gotNews) || (sharedPreferences.getBoolean("concertsChecked", true) && gotTourDates) ){
									new DJSpeech().execute();
								}
							}
							Message update = new Message();
							update.what = 0;
							UIHandler.sendMessage(update);
							synchronized (this) {
								while (UIwait) {
									try {
										wait();
									} catch (Exception e) {
									}
								}
							}
						}
					}
				} catch (Exception e) {
				}

				try {
					if (!MusicService.mPlayer.isPlaying()) {
						Message paused = new Message();
						paused.what = 1;
						UIHandler.sendMessage(paused);
					} else {
						Message playing = new Message();
						playing.what = 2;
						UIHandler.sendMessage(playing);
					}
					synchronized (this) {
						while (UIwait) {
							try {
								wait();
							} catch (Exception e) {
							}
						}
					}
				} catch (NullPointerException e) {
				}
				try {
					Thread.sleep(700);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	};

	public void onResume() {
		super.onResume();
		try {
			SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
		userEmail = sharedPreferences.getString("gmail", "");
		userPassword = Settings.decrypt("ThisIsMyEncryptionSeed", sharedPreferences.getString("password", ""));
		} catch (Exception e){
			e.printStackTrace();
		}
		if (updatingDatabase){
			mSongList.setTextColor(Color.parseColor("#99CC00"));
			albumTitle.setTextColor(Color.parseColor("#99CC00"));
			songTitle.setTextColor(Color.parseColor("#99CC00"));
			artistTitle.setTextColor(Color.parseColor("#99CC00"));
		}
		else if (generatingPlaylist){
			
		}
		else {
			mSongList.setTextColor(Color.parseColor("#FFFFFF"));
			albumTitle.setTextColor(Color.parseColor("#FFFFFF"));
			songTitle.setTextColor(Color.parseColor("#FFFFFF"));
			artistTitle.setTextColor(Color.parseColor("#FFFFFF"));
		}
		
		
		// This allows for scrolling text it is too large to be shown in the
		// space provided. Is here to let it work on orientation change,
		// although it does not.

		songTitle.setSelected(true);
		songTitle.setEllipsize(TruncateAt.MARQUEE);
		songTitle.setSingleLine(true);

		albumTitle.setSelected(true);
		albumTitle.setEllipsize(TruncateAt.MARQUEE);
		albumTitle.setSingleLine(true);

		artistTitle.setSelected(true);
		artistTitle.setEllipsize(TruncateAt.MARQUEE);
		artistTitle.setSingleLine(true);

		// While this will be handled by a thread every second, that second can
		// be noticed. Here we update the UI as soon as the user can see the
		// screen.

		try {
			Message position = new Message();
			position.what = MusicService.mPlayer.getCurrentPosition();
			threadHandler.sendMessage(position);
			Message update = new Message();
			update.what = 0;
			UIHandler.sendMessage(update);
			if (!MusicService.mPlayer.isPlaying()) {
				Message paused = new Message();
				paused.what = 1;
				UIHandler.sendMessage(paused);
			} else {
				Message playing = new Message();
				playing.what = 2;
				UIHandler.sendMessage(playing);
			}
		} catch (Exception e) {
		}
	}

	/**
	 * Checks online services every 20 mins to try find an update .
	 */
	Thread OnlineChecker = new Thread() {

		public synchronized void run() {

			while (true) {

				if (djMode) {

					try {
						Gmail(userEmail, userPassword);
						news();
						if (!mentionedTourArtists.contains(MusicRetriever.getCurrentSong().getArtist())){
							tourDates(MusicRetriever.getCurrentSong().getArtist());
						}
					} catch (Exception e) {
						e.printStackTrace();
					}
					try {
						wait(600000);
					} catch (InterruptedException e) {
					}
					try {
						wait(600000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}

				} else {
					try {
						wait(200000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}

		}
	};

	/**
	 * Updates the seek bar position once every second and checks if the DJ timeout should be enabled.
	 */
	Thread thread = new Thread() {

		Context ctx = (Context) MainFragment.this.getActivity();

		public synchronized void run() {

			while (true) {

				while (MusicService.mPlayer != null) {

					

					while (MusicService.State.Playing != null) {
						
						if (MusicService.mState == MusicService.State.Paused && djMode) {
							
							djModeTimeout++;
						}
						else {
							djModeTimeout = 0;
						}
						if (djModeTimeout > 1800) {
							djMode = false;
							Toast.makeText(ctx, "DJ off", Toast.LENGTH_SHORT)
									.show();
							djModeTimeout = 0;
						}
						
						try {
							Message position = new Message();
							position.what = MusicService.mPlayer
									.getCurrentPosition();
							threadHandler.sendMessage(position);
						} catch (NullPointerException e) {
						}
						try {
							Thread.sleep(1000);
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
					}
				}
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}

		}
	};

	private Handler threadHandler = new Handler() {

		/**
		 * Takes the current position of the song as the message parameter and
		 * updates the Seekbar accordingly. Also updates the time passed and
		 * time remaining indicators.
		 */
		public synchronized void handleMessage(Message msg) {
			mSeekbar.setProgress(msg.what);
			progress.setProgress(msg.what);
			timeProgressed = msg.what;
			try {
				timeRemaining = MusicRetriever.getCurrentSong().getDuration()
						- timeProgressed;
			} catch (Exception e) {
				e.printStackTrace();
			}
			timeProgressed = timeProgressed / 1000;
			timeRemaining = timeRemaining / 1000;
			progressed.setText(String.format("%d:%02d", timeProgressed / 60,
					timeProgressed % 60));
			remaining.setText(String.format("%d:%02d", timeRemaining / 60,
					timeRemaining % 60));
		}
	};

	public Handler UIHandler = new Handler() {

		/**
		 * Deals with updating the main interface screen. If the message == 0,
		 * then the artist, song and album text/art is updated and the size of
		 * the seekbar is set to the length of the song
		 **/
		public synchronized void handleMessage(Message msg) {
			if (msg.what == 0) {
				try {
					artistTitle.setText(MusicRetriever.getCurrentSong()
							.getArtist().toString());
					songTitle.setText(MusicRetriever.getCurrentSong()
							.getTitle().toString());
					albumTitle.setText(MusicRetriever.getCurrentSong()
							.getAlbum().toString());
					mSeekbar.setMax((int) MusicRetriever.getCurrentSong()
							.getDuration());
					progress.setMax((int) MusicRetriever.getCurrentSong()
							.getDuration());
					mAlbumArt.setImageBitmap(MusicRetriever.getArtForDisplay());
				} catch (Exception e) {
					mAlbumArt.setImageBitmap(null);
					e.printStackTrace();
				}
			} else if (msg.what == 1) {
				mPlayButton.setVisibility(View.VISIBLE);
				mPauseButton.setVisibility(View.GONE);
			} else if (msg.what == 2) {
				mPlayButton.setVisibility(View.GONE);
				mPauseButton.setVisibility(View.VISIBLE);
			}
		}
	};

	// Projection array. Creating indices for this array instead of doing
	// dynamic lookups improves performance.
	public static final String[] EVENT_PROJECTION = new String[] {
			Calendars._ID, // 0
			Calendars.ACCOUNT_NAME, // 1
			Calendars.CALENDAR_DISPLAY_NAME // 2
	};

	// The indices for the projection array above.
	private static final int PROJECTION_ID_INDEX = 0;
	private static final int PROJECTION_ACCOUNT_NAME_INDEX = 1;
	private static final int PROJECTION_DISPLAY_NAME_INDEX = 2;

	public void tourDates(String artist) {
		
		tour.clear();
		tourArtist = null;

		Context ctx = (Context) MainFragment.this.getActivity();
		LocationManager locationManager = (LocationManager) ctx
				.getSystemService(Context.LOCATION_SERVICE);
		String locationProvider = LocationManager.NETWORK_PROVIDER;
		Location lastKnownLocation = locationManager
				.getLastKnownLocation(locationProvider);

		PaginatedResult<Event> localEvents = Geo.getEvents(
				lastKnownLocation.getLatitude(),
				lastKnownLocation.getLongitude(), "50", LAST_API_KEY);

		for (Event localEvent : localEvents.getPageResults()) {
			if (localEvent.getArtists().contains(artist)) {
				tour.add(localEvent);
				tourArtist = artist;
				gotTourDates = true;
				System.out.println(artist
						+ "  playing at "
						+ localEvent.getVenue().getName()
						+ " on "
						+ localEvent
								.getEndDate()
								.toGMTString()
								.subSequence(
										0,
										localEvent.getEndDate().toGMTString()
												.length() - 9));
			}

		}

	}

	@SuppressWarnings("unused")
	public void calender() {

		Context ctx = (Context) MainFragment.this.getActivity();
		// Run query
		Cursor cur = null;
		ContentResolver cr = ctx.getContentResolver();
		Uri uri = Calendars.CONTENT_URI;
		String selection = "((" + Calendars.ACCOUNT_NAME + " = ?) AND ("
				+ Calendars.ACCOUNT_TYPE + " = ?))";
		String[] selectionArgs = new String[] { "",
				"com.google" };

		// Submit the query and get a Cursor object back.
		cur = cr.query(uri, EVENT_PROJECTION, selection, selectionArgs, null);

		while (cur.moveToNext()) {
			long calID = 0;
			String displayName = null;
			String accountName = null;

			// Get the field values
			calID = cur.getLong(PROJECTION_ID_INDEX);
			displayName = cur.getString(PROJECTION_DISPLAY_NAME_INDEX);
			accountName = cur.getString(PROJECTION_ACCOUNT_NAME_INDEX);

		}
		cur.close();
	}

	// Database / API methods. TODO:Move into own class.

	private EchoNestAPI en;

	String FILENAME = "LastFMCache";
	public static String ECHO_API_KEY = "A7VQWPKE9IXWKISV4";
	public static String LAST_API_KEY = "0dd8f343c12d70f548c0f0aa28737568";


	private void processQueryRequest(String artist, String song)
			throws EchoNestException {

		try {
			constructPlaylist(MusicRetriever.getCurrentSong());
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

	}

	public void searchSongsByArtist(String artist, int results)
			throws EchoNestException {
		Params p = new Params();
		p.add("artist", artist);
		p.add("bucket", "audio_summary");
		p.add("bucket", "artist_hotttnesss");
		p.add("results", results);

		Params q = new Params();
		q.add("name", artist);
		q.add("results", 10);

		List<com.echonest.api.v4.Artist> similar = en.getSimilarArtists(q);
		for (com.echonest.api.v4.Artist performer : similar) {
			System.out.println("Similar to " + artist + " = "
					+ performer.getName());
			System.out.println(performer.getTerms().get(1).getName() + ","
					+ performer.getTerms().get(2).getName());
		}
	}



	/**
	 * Takes a given item, calls the required API services and adds this
	 * information to the database
	 * 
	 * @param i
	 *            - The item to add to the database
	 * @throws EchoNestException
	 */
	public void addToDatabase(Item i) throws EchoNestException {

		en = new EchoNestAPI(ECHO_API_KEY);
		en.setTraceSends(false);
		en.setTraceRecvs(false);

		Context ctx = (Context) MainFragment.this.getActivity();

		long id = i.getId();
		String artist = i.getArtist();
		String title = i.getTitle();
		double dancability = 0;
		double energy = 0;
		double loudness = 0;
		double duration = 0;
		double tempo = 0;
		double mode = 0;
		double timesig = 0;
		String tagsString = "";

		Params p = new Params();
		p.add("artist", artist);
		p.add("title", title);
		p.add("results", 1);
		List<Song> EchoSong = en.searchSongs(p);
		try {
			Track LastSong = Track.getInfo(artist, title, LAST_API_KEY);
			Collection<String> tags = LastSong.getTags();
			tagsString = tags.toString();
		} catch (Exception e) {
		}
		for (Song track : EchoSong) {

			dancability = track.getDanceability();
			energy = track.getEnergy();
			loudness = track.getLoudness();
			duration = track.getDuration();
			tempo = track.getTempo();
			mode = track.getMode();
			timesig = track.getTimeSignature();
		}

		ContentValues values = new ContentValues();

		values.put(SongInfoStore.COLUMN_ID, id);
		values.put(SongInfoStore.COLUMN_ARTIST, artist);
		values.put(SongInfoStore.COLUMN_TITLE, title);
		values.put(SongInfoStore.COLUMN_DANCE, dancability);
		values.put(SongInfoStore.COLUMN_ENERGY, energy);
		values.put(SongInfoStore.COLUMN_LOUD, loudness);
		values.put(SongInfoStore.COLUMN_LENGTH, duration);
		values.put(SongInfoStore.COLUMN_TEMPO, tempo);
		values.put(SongInfoStore.COLUMN_TIMESIG, timesig);
		values.put(SongInfoStore.COLUMN_MODE, mode);
		values.put(SongInfoStore.COLUMN_TERMS, tagsString);

		try {
			cr.insert(
					SongInfoStoreContentProvider.CONTENT_URI, values);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 
	 * @param a
	 *            - The track currently being compared against the user's song
	 * @param b
	 *            - The track the user selected to base their playlist on
	 * @return A numerical indication of how similar a and b are. A lower number
	 *         represents a more similar song.
	 * @throws EchoNestException
	 */
	public double calculateSimilarity(Item a, BaseSong b)
			throws EchoNestException {

		Context ctx = (Context) MainFragment.this.getActivity();

		double dancability1 = 0;
		double energy1 = 0;
		double loudness1 = 0;
		double duration1 = 0;
		double tempo1 = 0;
		double mode1 = 0;
		double timesig1 = 0;
		Collection<String> tags1 = null;

		double dancability2 = 0;
		double energy2 = 0;
		double loudness2 = 0;
		double duration2 = 0;
		double tempo2 = 0;
		double mode2 = 0;
		double timesig2 = 0;
		Collection<String> tags2 = null;

		double dancabilityDiff = 0;
		double energyDiff = 0;
		double tempoDiff = 0;
		double durationDiff = 0;
		double loudnessDiff = 0;
		int modeDiff = 0;
		int timesigDiff = 0;
		int similarTerms = 0;

		double finalScore = 0;

		String[] projection = { SongInfoStore.COLUMN_ID,
				SongInfoStore.COLUMN_ARTIST/* , SongInfoStore.COLUMN_ALBUM */,
				SongInfoStore.COLUMN_DANCE, SongInfoStore.COLUMN_ENERGY,
				SongInfoStore.COLUMN_TEMPO, SongInfoStore.COLUMN_LENGTH,
				SongInfoStore.COLUMN_LOUD, SongInfoStore.COLUMN_MODE,
				SongInfoStore.COLUMN_TIMESIG, SongInfoStore.COLUMN_TERMS };

		Uri uri = SongInfoStoreContentProvider.CONTENT_URI;

		Cursor cursor = cr.query(
				uri,
				projection,
				SongInfoStore.COLUMN_ARTIST + " = ? AND "
						+ SongInfoStore.COLUMN_TITLE + " = ? "/*
															 * + SongInfoStore.
															 * COLUMN_ALBUM +
															 * " = ?"
															 */,
				new String[] { String.valueOf(a.getArtist()),
						String.valueOf(a.getTitle()), /*
													 * String.valueOf(a.getAlbum(
													 * ))
													 */}, null);
		cursor.moveToFirst();
		String dancability = cursor.getString(cursor
				.getColumnIndexOrThrow(SongInfoStore.COLUMN_DANCE));
		String energy = cursor.getString(cursor
				.getColumnIndexOrThrow(SongInfoStore.COLUMN_ENERGY));
		String loudness = cursor.getString(cursor
				.getColumnIndexOrThrow(SongInfoStore.COLUMN_LOUD));
		String duration = cursor.getString(cursor
				.getColumnIndexOrThrow(SongInfoStore.COLUMN_LENGTH));
		String tempo = cursor.getString(cursor
				.getColumnIndexOrThrow(SongInfoStore.COLUMN_TEMPO));
		String mode = cursor.getString(cursor
				.getColumnIndexOrThrow(SongInfoStore.COLUMN_MODE));
		String timesig = cursor.getString(cursor
				.getColumnIndexOrThrow(SongInfoStore.COLUMN_TIMESIG));
		String terms = cursor.getString(cursor
				.getColumnIndexOrThrow(SongInfoStore.COLUMN_TERMS));
		cursor.close();

		dancability1 = Double.parseDouble(dancability);
		energy1 = Double.parseDouble(energy);
		loudness1 = Double.parseDouble(loudness);
		duration1 = Double.parseDouble(duration);
		tempo1 = Double.parseDouble(tempo);
		mode1 = Double.parseDouble(mode);
		timesig1 = Double.parseDouble(timesig);
		try {
			String aTerms = terms.substring(1, terms.length() - 1);
			tags1 = new ArrayList<String>(Arrays.asList(aTerms.split(", ")));
		} catch (Exception e) {
		}

		// Check if song has this information, if not then don't consider it for
		// playlist generation by assigning a large score.
		if (dancability1 == 0 && energy1 == 0 && loudness1 == 0
				&& duration1 == 0) {
			finalScore = 100;
			return finalScore;
		}

		dancability2 = b.getDance();
		energy2 = b.getEnergy();
		loudness2 = b.getLoudness();
		duration2 = b.getDuration();
		tempo2 = b.getTempo();
		mode2 = b.getMode();
		timesig2 = (b.getTimeSig());
		try {
			String bTerms = b.getTerms()
					.substring(1, b.getTerms().length() - 1);
			tags2 = new ArrayList<String>(Arrays.asList(bTerms.split(", ")));
		} catch (Exception e) {
		}
		if (dancability1 <= 0.2 && dancability1 > 0) {
			dancability1 = 1;
		} else if (dancability1 <= 0.4 && dancability1 > 0.2) {
			dancability1 = 2;
		} else if (dancability1 <= 0.6 && dancability1 > 0.4) {
			dancability1 = 3;
		} else if (dancability1 <= 0.8 && dancability1 > 0.6) {
			dancability1 = 4;
		} else if (dancability1 <= 1 && dancability1 > 0.8) {
			dancability1 = 5;
		}

		if (dancability2 <= 0.2 && dancability2 > 0) {
			dancability2 = 1;
		} else if (dancability2 <= 0.4 && dancability2 > 0.2) {
			dancability2 = 2;
		} else if (dancability2 <= 0.6 && dancability2 > 0.4) {
			dancability2 = 3;
		} else if (dancability2 <= 0.8 && dancability2 > 0.6) {
			dancability2 = 4;
		} else if (dancability2 <= 1 && dancability2 > 0.8) {
			dancability2 = 5;
		}

		if (energy1 <= 0.1 && energy1 > 0) {
			energy1 = 0.5;
		} else if (energy1 <= 0.2 && energy1 > 0.1) {
			energy1 = 1;
		} else if (energy1 <= 0.3 && energy1 > 0.2) {
			energy1 = 1.5;
		} else if (energy1 <= 0.4 && energy1 > 0.3) {
			energy1 = 2;
		} else if (energy1 <= 0.5 && energy1 > 0.4) {
			energy1 = 2.5;
		} else if (energy1 <= 0.6 && energy1 > 0.5) {
			energy1 = 3;
		} else if (energy1 <= 0.7 && energy1 > 0.6) {
			energy1 = 3.5;
		} else if (energy1 <= 0.8 && energy1 > 0.7) {
			energy1 = 4;
		} else if (energy1 <= 0.9 && energy1 > 0.8) {
			energy1 = 4.5;
		} else if (energy1 <= 1 && energy1 > 0.9) {
			energy1 = 5;
		}

		if (energy2 <= 0.1 && energy2 > 0) {
			energy2 = 0.5;
		} else if (energy2 <= 0.2 && energy2 > 0.1) {
			energy2 = 1;
		} else if (energy2 <= 0.3 && energy2 > 0.2) {
			energy2 = 1.5;
		} else if (energy2 <= 0.4 && energy2 > 0.3) {
			energy2 = 2;
		} else if (energy2 <= 0.5 && energy2 > 0.4) {
			energy2 = 2.5;
		} else if (energy2 <= 0.6 && energy2 > 0.5) {
			energy2 = 3;
		} else if (energy2 <= 0.7 && energy2 > 0.6) {
			energy2 = 3.5;
		} else if (energy2 <= 0.8 && energy2 > 0.7) {
			energy2 = 4;
		} else if (energy2 <= 0.9 && energy2 > 0.8) {
			energy2 = 4.5;
		} else if (energy2 <= 1 && energy2 > 0.9) {
			energy2 = 5;
		}

		if (loudness1 <= -35 && loudness1 > -40) {
			loudness1 = 0.5;
		} else if (loudness1 <= -30 && loudness1 > -35) {
			loudness1 = 1;
		} else if (loudness1 <= -25 && loudness1 > -20) {
			loudness1 = 1.5;
		} else if (loudness1 <= -17 && loudness1 > -20) {
			loudness1 = 2;
		} else if (loudness1 <= -11 && loudness1 > -14) {
			loudness1 = 2.5;
		} else if (loudness1 <= -9 && loudness1 > -11) {
			loudness1 = 3;
		} else if (loudness1 <= -7 && loudness1 > -9) {
			loudness1 = 3.5;
		} else if (loudness1 <= -5 && loudness1 > -6) {
			loudness1 = 4;
		} else if (loudness1 <= -4 && loudness1 > -5) {
			loudness1 = 4.5;
		} else if (loudness1 <= 0 && loudness1 > -4) {
			loudness1 = 5;
		} else {
			loudness1 = 0;
		}

		if (loudness2 <= -35 && loudness2 > -40) {
			loudness2 = 0.5;
		} else if (loudness2 <= -30 && loudness2 > -35) {
			loudness2 = 1;
		} else if (loudness2 <= -25 && loudness2 > -20) {
			loudness2 = 1.5;
		} else if (loudness2 <= -17 && loudness2 > -20) {
			loudness2 = 2;
		} else if (loudness2 <= -11 && loudness2 > -14) {
			loudness2 = 2.5;
		} else if (loudness2 <= -9 && loudness2 > -11) {
			loudness2 = 3;
		} else if (loudness2 <= -7 && loudness2 > -9) {
			loudness2 = 3.5;
		} else if (loudness2 <= -5 && loudness2 > -6) {
			loudness2 = 4;
		} else if (loudness2 <= -4 && loudness2 > -5) {
			loudness2 = 4.5;
		} else if (loudness2 <= 0 && loudness2 > -4) {
			loudness2 = 5;
		} else {
			loudness2 = 0;
		}

		if (tempo1 <= 80 && tempo1 > 0) {
			tempo1 = 0.5;
		} else if (tempo1 <= 90 && tempo1 > 80) {
			tempo1 = 1;
		} else if (tempo1 <= 100 && tempo1 > 90) {
			tempo1 = 1.5;
		} else if (tempo1 <= 110 && tempo1 > 100) {
			tempo1 = 2;
		} else if (tempo1 <= 120 && tempo1 > 110) {
			tempo1 = 2.5;
		} else if (tempo1 <= 130 && tempo1 > 120) {
			tempo1 = 3;
		} else if (tempo1 <= 150 && tempo1 > 130) {
			tempo1 = 3.5;
		} else if (tempo1 <= 170 && tempo1 > 150) {
			tempo1 = 4;
		} else if (tempo1 <= 190 && tempo1 > 170) {
			tempo1 = 4.5;
		} else if (tempo1 <= 500 && tempo1 > 190) {
			tempo1 = 5;
		}

		if (tempo2 <= 80 && tempo2 > 0) {
			tempo2 = 0.5;
		} else if (tempo2 <= 90 && tempo2 > 80) {
			tempo2 = 1;
		} else if (tempo2 <= 100 && tempo2 > 90) {
			tempo2 = 1.5;
		} else if (tempo2 <= 110 && tempo2 > 100) {
			tempo2 = 2;
		} else if (tempo2 <= 120 && tempo2 > 110) {
			tempo2 = 2.5;
		} else if (tempo2 <= 130 && tempo2 > 120) {
			tempo2 = 3;
		} else if (tempo2 <= 150 && tempo2 > 130) {
			tempo2 = 3.5;
		} else if (tempo2 <= 170 && tempo2 > 150) {
			tempo2 = 4;
		} else if (tempo2 <= 190 && tempo2 > 170) {
			tempo2 = 4.5;
		} else if (tempo2 <= 500 && tempo2 > 190) {
			tempo2 = 5;
		}

		if (duration1 <= 30 && duration1 > 0) {
			duration1 = 0.5;
		} else if (duration1 <= 60 && duration1 > 30) {
			duration1 = 1;
		} else if (duration1 <= 120 && duration1 > 60) {
			duration1 = 1.5;
		} else if (duration1 <= 180 && duration1 > 120) {
			duration1 = 2;
		} else if (duration1 <= 240 && duration1 > 180) {
			duration1 = 2.5;
		} else if (duration1 <= 180 && duration1 > 240) {
			duration1 = 3;
		} else if (duration1 <= 480 && duration1 > 240) {
			duration1 = 3.5;
		} else if (duration1 <= 720 && duration1 > 480) {
			duration1 = 4;
		} else if (duration1 <= 1440 && duration1 > 720) {
			duration1 = 4.5;
		} else if (duration1 <= 3600 && duration1 > 1440) {
			duration1 = 5;
		}

		if (duration2 <= 30 && duration2 > 0) {
			duration2 = 0.5;
		} else if (duration2 <= 60 && duration2 > 30) {
			duration2 = 1;
		} else if (duration2 <= 120 && duration2 > 60) {
			duration2 = 1.5;
		} else if (duration2 <= 180 && duration2 > 120) {
			duration2 = 2;
		} else if (duration2 <= 240 && duration2 > 180) {
			duration2 = 2.5;
		} else if (duration2 <= 180 && duration2 > 240) {
			duration2 = 3;
		} else if (duration2 <= 480 && duration2 > 240) {
			duration2 = 3.5;
		} else if (duration2 <= 720 && duration2 > 480) {
			duration2 = 4;
		} else if (duration2 <= 1440 && duration2 > 720) {
			duration2 = 4.5;
		} else if (duration2 <= 3600 && duration2 > 1440) {
			duration2 = 5;
		}

		if (dancability1 > dancability2) {
			dancabilityDiff = dancability1 - dancability2;
		} else {
			dancabilityDiff = dancability2 - dancability1;
		}

		if (energy1 > energy2) {
			energyDiff = energy1 - energy2;
		} else {
			energyDiff = energy2 - energy1;
		}

		if (tempo1 > tempo2) {
			tempoDiff = tempo1 - tempo2;
		} else {
			tempoDiff = tempo2 - tempo1;
		}

		if (loudness1 > loudness2) {
			loudnessDiff = loudness1 - loudness2;
		} else {
			loudnessDiff = loudness2 - loudness1;
		}

		if (duration1 > duration2) {
			durationDiff = duration1 - duration2;
		} else {
			durationDiff = duration2 - duration1;
		}

		if ((mode1 == mode2)) {
			modeDiff = 1;
		}

		if ((timesig1 != 4.0 && timesig2 != 4.0)) {
			timesigDiff = 1;
		}
		try {
			tags1.retainAll(tags2);
			similarTerms = tags1.size();
		} catch (Exception e) {
			similarTerms = 0;
		}

		// Lower number = more similar
		finalScore = (dancabilityDiff * 1.2) + (energyDiff * 2)
				+ (tempoDiff * 1.3) + durationDiff + modeDiff + timesigDiff
				+ (loudnessDiff * 1.2) - similarTerms;

		return finalScore;
	}

	/**
	 * Takes a song and checks if it exists in the database
	 * 
	 * @param artist
	 *            - The artist of the song
	 * @param title
	 *            - The title of the song
	 * @param album
	 *            - The album the song is from
	 * @return true if the song is in the database, false if it is not.
	 */
	public boolean Exists(String artist, String title, String album) {
		Context ctx = (Context) MainFragment.this.getActivity();
		Uri uri = SongInfoStoreContentProvider.CONTENT_URI;
		String[] projection = { SongInfoStore.COLUMN_ARTIST,
				SongInfoStore.COLUMN_TITLE};
		Cursor cursor = cr.query(
				uri,
				projection,
				SongInfoStore.COLUMN_ARTIST + " = ? AND "
						+ SongInfoStore.COLUMN_TITLE + " = ? ",
				new String[] { artist, title }, null);
		boolean exists = (cursor.getCount() > 0);
		cursor.close();
		return exists;
	}

	/**
	 * Goes through every song and checks if it is in the database. If a song is
	 * not found in the database it is added.
	 * 
	 * @throws EchoNestException
	 */
	public void fillDatabase() throws EchoNestException {

		for (Item track : MusicRetriever.mItems) {
			if (!Exists(track.getArtist(), track.getTitle(), track.getAlbum())) {
				SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
				SharedPreferences.Editor editor = sharedPreferences.edit();
				int prevsize = sharedPreferences.getInt("database", 0);
				editor.putInt("database", prevsize + 1);
				editor.commit();
				addToDatabase(track);
			} else {
				// Do nothing. Song already in database.
			}
		}
	}

	/**
	 * Creates a playlist comprising of 9 songs and a given a song i and sets
	 * that to be the current playlist
	 * 
	 * @param i
	 *            The song to base the playlist on
	 * @throws EchoNestException
	 */
	@SuppressWarnings("rawtypes")
	public void constructPlaylist(Item i) throws EchoNestException {
		Context ctx = (Context) MainFragment.this.getActivity();

		String[] projection = { SongInfoStore.COLUMN_ARTIST,
		SongInfoStore.COLUMN_TITLE, SongInfoStore.COLUMN_DANCE,
				SongInfoStore.COLUMN_ENERGY, SongInfoStore.COLUMN_TEMPO,
				SongInfoStore.COLUMN_LENGTH, SongInfoStore.COLUMN_LOUD,
				SongInfoStore.COLUMN_MODE, SongInfoStore.COLUMN_TIMESIG,
				SongInfoStore.COLUMN_TERMS };

		Uri uri = SongInfoStoreContentProvider.CONTENT_URI;

		Cursor cursor = cr.query(
				uri,
				projection,
				SongInfoStore.COLUMN_ARTIST + " = ? AND "
						+ SongInfoStore.COLUMN_TITLE + " = ? ",
				new String[] { String.valueOf(i.getArtist()),
						String.valueOf(i.getTitle())}, null);
		if (!(cursor.getCount() > 0)) {
			// Original song not in database, cannot make playlist
			
			Toast.makeText(ctx, "Track not in database", Toast.LENGTH_SHORT).show();
 
			return;
		}
		cursor.moveToFirst();
		String dancability = cursor.getString(cursor
				.getColumnIndexOrThrow(SongInfoStore.COLUMN_DANCE));
		String energy = cursor.getString(cursor
				.getColumnIndexOrThrow(SongInfoStore.COLUMN_ENERGY));
		String loudness = cursor.getString(cursor
				.getColumnIndexOrThrow(SongInfoStore.COLUMN_LOUD));
		String duration = cursor.getString(cursor
				.getColumnIndexOrThrow(SongInfoStore.COLUMN_LENGTH));
		String tempo = cursor.getString(cursor
				.getColumnIndexOrThrow(SongInfoStore.COLUMN_TEMPO));
		String mode = cursor.getString(cursor
				.getColumnIndexOrThrow(SongInfoStore.COLUMN_MODE));
		String timesig = cursor.getString(cursor
				.getColumnIndexOrThrow(SongInfoStore.COLUMN_TIMESIG));
		String terms = cursor.getString(cursor
				.getColumnIndexOrThrow(SongInfoStore.COLUMN_TERMS));
		cursor.close();

		BaseSong base = new BaseSong(i.getId(), i.getArtist(), i.getTitle(),
				i.getAlbum(), Double.parseDouble(duration), i.getAlbumID(),
				Double.parseDouble(dancability), Double.parseDouble(energy),
				Double.parseDouble(loudness), Double.parseDouble(tempo),
				Double.parseDouble(mode), Double.parseDouble(timesig), terms);

		ArrayList<MyEntry<Item, Double>> generatedPlaylist = new ArrayList<MyEntry<Item, Double>>();

		for (Item trackSong : MusicRetriever.mItems) {
			generatedPlaylist.add(new MyEntry<Item, Double>(trackSong,
					calculateSimilarity(trackSong, base)));
		}

		Collections.sort(generatedPlaylist, new Comparator<MyEntry>() {

			public int compare(MyEntry o1, MyEntry o2) {
				Double i1 = (Double) o1.getValue();
				Double i2 = (Double) o2.getValue();
				return i1.compareTo(i2);
			}
		});
		int d = 1;
		MusicRetriever.generatedPlaylist.clear();
		try {
			MusicRetriever.generatedPlaylist.add(MusicRetriever
					.getCurrentSong());
			MusicRetriever.mposition = -1;

		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		while (MusicRetriever.generatedPlaylist.size() < 10) {
			try {
			try {
			if (!(generatedPlaylist.get(d).getKey().getArtist()
					.equalsIgnoreCase(generatedPlaylist.get(d - 1).getKey()
							.getArtist()))
					&& (!(generatedPlaylist.get(d).getKey().getTitle()
							.equalsIgnoreCase(generatedPlaylist.get(d - 1)
									.getKey().getTitle())))) {
				
				MusicRetriever.generatedPlaylist.add(generatedPlaylist.get(d).getKey());
			}
			} catch (Exception e){
				
		        MusicRetriever.generatedPlaylist.add(generatedPlaylist.get(d).getKey());
			}
			} catch (Exception e) {
				break;
			}
			d++;
		}
		Item temp;
		temp = MusicRetriever.generatedPlaylist.get(0);
		MusicRetriever.generatedPlaylist.remove(0);
		Collections.shuffle(MusicRetriever.generatedPlaylist);
		MusicRetriever.generatedPlaylist.add(0, temp);
		MusicRetriever.usingPlaylist = false;
		MusicRetriever.mainSongList = false;
		MusicRetriever.usingGenPlaylist = true;
		if (MusicRetriever.shuffle) {
			MusicRetriever.shuffle = false;
			ctx.startService(new Intent(MusicService.ACTION_SHUFFLE));
		}

	}

	/**
	 * Essentially used a tuple to enable each song to be given a corresponding
	 * similarity. The Key is the item (or song) and the value is the similarity
	 * index.
	 */
	public class MyEntry<K, V> implements Entry<K, V> {
		private final K key;
		private V value;

		public MyEntry(final K key) {
			this.key = key;
		}

		public MyEntry(final K key, final V value) {
			this.key = key;
			this.value = value;
		}

		public K getKey() {
			return key;
		}

		public V getValue() {
			return value;
		}

		public V setValue(final V value) {
			final V oldValue = this.value;
			this.value = value;
			return oldValue;
		}
	}
	 
	private RSSFeed getFeed(String urlToRssFeed)
    {
    	try
    	{
    		// setup the url
    	   URL url = new URL(urlToRssFeed);

           // create the factory
           SAXParserFactory factory = SAXParserFactory.newInstance();
           // create a parser
           SAXParser parser = factory.newSAXParser();

           // create the reader (scanner)
           XMLReader xmlreader = parser.getXMLReader();
           // instantiate our handler
           RSSHandler theRssHandler = new RSSHandler();
           // assign our handler
           xmlreader.setContentHandler(theRssHandler);
           // get our data via the url class
           InputSource is = new InputSource(url.openStream());
           // perform the synchronous parse           
           xmlreader.parse(is);
           // get the results - should be a fully populated RSSFeed instance, or null on error
           return theRssHandler.getFeed();
    	}
    	catch (Exception ee)
    	{
    		// if we have a problem, simply return null
    		return null;
    	}
    }

	

	public void news(){

		feed = getFeed(RSSFEED);
		
		headlines.add(feed.getItem(0).getTitle());
		headlines.add(feed.getItem(1).getTitle());
		headlines.add(feed.getItem(2).getTitle());
		headlines.add(feed.getItem(3).getTitle());
		headlines.add(feed.getItem(4).getTitle());

		
		gotNews = true;

	}

	/**
	 * 
	 * Gets the subjects of the 3 most recent e-mails for the given user.
	 * 
	 * @param username
	 *            A string representing the email address
	 * @param password
	 *            A string representing the password
	 * @throws MessagingException
	 * 
	 */
	public void Gmail(String username, String password)
			throws MessagingException {

		emails.clear();
		Properties props = new Properties();
		javax.mail.Session session = javax.mail.Session.getDefaultInstance(
				props, null);
		Store store = session.getStore("imaps");
		store.connect("imap.gmail.com", username, password);
		Folder inbox = store.getFolder("Inbox");
		inbox.open(Folder.READ_ONLY);
		newEmailNumber = inbox.getMessageCount();
		if (newEmailNumber > oldEmailNumber) {
			int i = newEmailNumber - oldEmailNumber;
			try {
				javax.mail.Message[] messages = inbox.getMessages(
						inbox.getMessageCount() - i + 1,
						inbox.getMessageCount());
				for (javax.mail.Message message : messages) {
					emails.add(0, message.getSubject());
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
			if (!emailSetup){
				emailSetup = true;
			}
			else {
				gotMail = true;

			}
			
		}
		oldEmailNumber = newEmailNumber;
	}

	// Twitter is not used at the moment, and may not be.



	/**
	 * A representation of the song given to construct a playlist from. Stores
	 * more than a typical MusicRetreiver Item to facilitate fewer database
	 * calls when constructing a playlist
	 */
	public static class BaseSong {
		long id;
		String artist;
		String title;
		String album;
		double duration;
		long albumID;
		String terms;
		double timesig;
		double mode;
		double tempo;
		double loudness;
		double energy;
		double dance;

		public BaseSong(long id, String artist, String title, String album,
				double duration, long albumID, double dance, double energy,
				double loudness, double tempo, double mode, double timesig,
				String terms) {
			this.id = id;
			this.artist = artist;
			this.title = title;
			this.album = album;
			this.duration = duration;
			this.albumID = albumID;
			this.dance = dance;
			this.energy = energy;
			this.loudness = loudness;
			this.tempo = tempo;
			this.mode = mode;
			this.timesig = timesig;
			this.terms = terms;
		}

		public long getId() {
			return id;
		}

		public String getArtist() {
			return artist;
		}

		public String getTitle() {
			return title;
		}

		public String getAlbum() {
			return album;
		}

		public double getDuration() {
			return duration;
		}

		public long getAlbumID() {
			return albumID;
		}

		public double getDance() {
			return dance;
		}

		public double getEnergy() {
			return energy;
		}

		public double getLoudness() {
			return loudness;
		}

		public double getTempo() {
			return tempo;
		}

		public double getMode() {
			return mode;
		}

		public double getTimeSig() {
			return timesig;
		}

		public String getTerms() {
			return terms;
		}
	}

	public void onInit(int status) {

	}

}